Here we use Phea to compute the overt disseminated intravascular coagulation score produced by the International Society for Thrombosis and Hemostasis:

For this vignette, we will assume you have a SQL server at localhost, with patient data in OMOP Common Data Model v5.4 format, inside schema cdm_new_york3.

This vignette was produced using synthetic data generated by Synthea Patient Generator and ETL’d into OMOP CDM v5.4 by ETL-Synthea. Lots of thanks to both projects!

Setup Phea

First we connect to the server. Calling setup_phea() is optional, but it enables the convenience functions slqt() and sql0().

library(phea)
suppressPackageStartupMessages(library(dplyr))

# Connect to SQL server.
dbcon <- DBI::dbConnect(
    RPostgres::Postgres(),
    host = 'localhost', port = 7654, dbname = 'fort',
    user = cred$pg$user, password = cred$pg$pass)

# Provide the connection to Phea so we can use the sqlt() and sql0() shorthands.
setup_phea(dbcon, 'cdm_new_york3')

Create components

Let component d_dimer be records from table MEASUREMENT where measurement_concept_id is equal to 3051714.

# LOINC code 48065-7 Fibrin D-dimer FEU [Mass/volume] in Platelet poor plasma
# OMOP CDM concept ID 3051714
d_dimer <- sqlt(measurement) |>
  filter(measurement_concept_id == 3051714) |>
  make_component(
    .pid = person_id,
    .ts = measurement_datetime)

Let component inr be records from table MEASUREMENT where measurement_concept_id is equal to 3022217.

# LOINC code 6301-6 INR in Platelet poor plasma by Coagulation assay
# OMOP CDM concept ID 3022217
inr <- sqlt(measurement) |>
  filter(measurement_concept_id == 3022217) |>
  make_component(
    .pid = person_id,
    .ts = measurement_datetime)

Let component platelet be records from table MEASUREMENT where measurement_concept_id is equal to 3024929.

# LOINC code 777-3 Platelets [#/volume] in Blood by Automated count
# OMOP CDM concept ID 3024929
platelet <- sqlt(measurement) |>
  filter(measurement_concept_id == 3024929) |>
  make_component(
    .pid = person_id,
    .ts = measurement_datetime)

Calculate the phenotype

The phenotype logic can be regarded as having two steps:

  1. first you interpret the values, i.e. compare to their thresholds, e.g. is platelet count under 50,000?
  2. then you add the points to produce the final answer yes there is overt DIC or no there is no overt DIC.

We will accomplish that using a sequence of formulas.

dic_score <- calculate_formula(
  components = list(
    d_dimer = d_dimer,
    inr = inr,
    platelet = platelet),
  fml = list(
    d_dimer_points = 'case
      when d_dimer_value_as_number >= 4 then 3
      when d_dimer_value_as_number >= 0.4 then 2
      when d_dimer_value_as_number < 0.4 then 0
      else null end',
    inr_points = 'case
      when inr_value_as_number <= 1.2 then 0
      when inr_value_as_number <= 1.7 then 1
      when inr_value_as_number > 1.7 then 2
      else null end',
    platelet_points = 'case
      when platelet_value_as_number < 50 then 2
      when platelet_value_as_number <= 100 then 1
      when platelet_value_as_number > 100 then 0
      else 0 end',
    isth_score = 'd_dimer_points + inr_points + platelet_points',
    overt_dic = 'case when isth_score >= 5 then 1 else 0 end'),
  window = '2 days')

Plot the phenotype result

if(!exists('pids'))
  pids <- dic_score |>
    select(pid) |>
    distinct() |>
    pull()
phea_plot(dic_score, sample(pids, 1))
#> Collecting lazy table, done. (turn this message off with `verbose = FALSE`)
#> Warning in min(chart_data$value, na.rm = TRUE): no non-missing arguments to min; returning Inf
#> Warning in max(chart_data$value, na.rm = TRUE): no non-missing arguments to max; returning -Inf
#> Warning in min(chart_data$value, na.rm = TRUE): no non-missing arguments to min; returning Inf
#> Warning in max(chart_data$value, na.rm = TRUE): no non-missing arguments to max; returning -Inf
#> Warning in min(chart_data$value, na.rm = TRUE): no non-missing arguments to min; returning Inf
#> Warning in max(chart_data$value, na.rm = TRUE): no non-missing arguments to max; returning -Inf
#> Warning in min(chart_data$value, na.rm = TRUE): no non-missing arguments to min; returning Inf
#> Warning in max(chart_data$value, na.rm = TRUE): no non-missing arguments to max; returning -Inf
#> Warning in min(chart_data$value, na.rm = TRUE): no non-missing arguments to min; returning Inf
#> Warning in max(chart_data$value, na.rm = TRUE): no non-missing arguments to max; returning -Inf

Compute aggregates from a phenotype result

Obtain SQL query that computes the phenotype